package com.example.upload.config;


import com.example.upload.exception.BusinessException;
import com.example.upload.exception.BusinessRuntimeException;
import com.example.upload.response.ResponseResult;
import com.example.upload.response.ResponseResultFactory;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 拦截业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseResult handlerBusinessException(BusinessException e) {
        log.error("业务异常:", e);
        return ResponseResultFactory.build(1, e.getMessage());
    }




    private static final String ERROR_MSG = "系统内部异常";

    //请求的JSON数据格式不正确，抛出的异常时HttpMessageNotReadableException异常。
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public ResponseResult HttpIllegalArgumentExceptionHandler(IllegalArgumentException e) {
        log.error(e.getMessage(), e);
        return ResponseResultFactory.build(1, e.getMessage());
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(BusinessRuntimeException.class)
    @ResponseBody
    public ResponseResult handlerBusinessRuntimeException(BusinessRuntimeException e) {
        log.error(e.getMessage(), e);
        return ResponseResultFactory.build(1, e.getMessage());
    }


    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public ResponseResult handlerRuntimeException(RuntimeException e) {
        log.error("运行时异常:", e);
        return ResponseResultFactory.build(1, "服务器错误，请联系管理员！");
    }



    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseResult exceptionHandler(HttpServletRequest req, Exception e) {
        log.error(ERROR_MSG, e);
        return ResponseResultFactory.build(1,"服务器错误，请联系管理员");
    }

    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public ResponseResult bindExceptionHandler(HttpServletRequest req, BindException e) {
        log.error("",e);
        List<FieldError> fieldErrors = e.getFieldErrors();
        StringBuilder errorBuilder = new StringBuilder();
        for (FieldError fieldError : fieldErrors) {
            errorBuilder.append("["+fieldError.getField()+ "]"+fieldError.getDefaultMessage()).append(" ");
            return ResponseResultFactory.buildFailResponse(errorBuilder.toString());
        }
        return ResponseResultFactory.buildFailResponse(errorBuilder.toString());
    }


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseResult methodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e) {
        log.error("",e);
        BindingResult result = e.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();
        StringBuilder errorBuilder = new StringBuilder();
        for (FieldError fieldError : fieldErrors) {
            errorBuilder.append("["+fieldError.getField()+ "]"+fieldError.getDefaultMessage()).append(" ");
            return ResponseResultFactory.buildFailResponse(errorBuilder.toString());
        }
        return ResponseResultFactory.buildFailResponse(errorBuilder.toString());
    }


    //请求的JSON数据格式不正确，抛出的异常时HttpMessageNotReadableException异常。
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public ResponseResult HttpMessageNotReadableExceptionHandler(HttpMessageNotReadableException e) {
        log.error(e.getMessage(), e);
        return ResponseResultFactory.build(1, "请求的参数不正确！");
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseBody
    public ResponseResult constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException e) {
        log.error("",e);
        StringBuilder errorBuilder = new StringBuilder();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            PathImpl path = (PathImpl) violation.getPropertyPath();
            errorBuilder.append(path.getLeafNode().getName())
                .append(":")
                .append(violation.getMessage())
                .append(" ");
        }
        return ResponseResultFactory.buildFailResponse(errorBuilder.toString());
    }

    /**
     * 处理请求头类型不正确的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    @ResponseBody
    public ResponseResult handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        log.error(e.getMessage(), e);
        return ResponseResultFactory.build(1, "不支持的请求头:[" + e.getMessage() + "]!");
    }


}
